//
// This file is part of cpp-lib, a library of C++ functions and classes.
// Cpp-lib is copyright (C) 2004 and onwards, The CPL Interest Group.
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or (at
// your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
// General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library (see the file COPYING); if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
// 02111-1307  USA
//
// $Id$
//


#ifndef CPP_LIB_UTIL_SYS_H
#define CPP_LIB_UTIL_SYS_H

#include "cpp-lib/util.h"
#include "cpp-lib/registry.h"
#include "cpp-lib/sys/file.h"

//
// Headers for functionality that has an OS-independent interface but
// needs to be implemented in an OS specific way.
//
// Includes:
//   time(), sleep()
//   reboot(), poweroff()
//   sleep_scheduler
//   watched_registry
//


namespace cpl {

namespace util {

//
// Sleep for the specified time [s].  Accuracy is system-dependent,
// typically in the range of 10 milliseconds.
//

void sleep( double const& ) ;

//
// Return time since some fixed epoch.  Accuracy is system-dependent,
// typically in the range of 10 milliseconds.
//

double time() ;

//
// Terminate all processes and reboot.
//

void reboot() ;

//
// Terminate all processes and switch power off.
//

void poweroff() ;


struct sleep_scheduler {

  // Fire at t_0 + i * dt.
  sleep_scheduler( double const& dt , double const& t_0 = 0 )
  : dt    ( dt     ) ,
    hz    ( 1 / dt ) ,
    t_0   ( t_0    ) ,
    n_next( -std::numeric_limits< double >::max() )

  {

    always_assert( 0 < dt        ) ;
    always_assert( 0 <= t_0      ) ; // really necessary?
    always_assert(      t_0 < dt ) ; // really necessary?

  }

  double wait_next() ;

  double time() { return cpl::util::time() ; }


private:

  double const dt  ;
  double const hz  ;
  double const t_0 ;

  double n_next ;

} ;


//
// A registry with the ability to bind to a file, detect changes and
// re-read it in this case.
//

struct watched_registry : registry {

  //
  // Read from named file and bind to the file name for update checking.
  //

  virtual void read_from(
    std::string const& name                               ,
     lexer_style_t const&  lexer_style = lexer_style_t () ,
    parser_style_t const& parser_style = parser_style_t() ,
    bool throw_on_redefinition = true
  ) {

    registry::read_from
    ( name , lexer_style , parser_style , throw_on_redefinition ) ;

    ls =  lexer_style ;
    ps = parser_style ;

    w.reset( new cpl::util::file::file_name_watcher( name ) ) ;

  }

  virtual void read_from(
    std::string const& name                ,
    grammar     const& g       = grammar() ,
    bool throw_on_redefinition = true
  ) {

    read_from
    ( name , g.lexer_style , g.parser_style , throw_on_redefinition ) ;

  }


  //
  // Re-read the registry if a change in the file has been detected.
  // Return true in this case.
  //

  bool read_if_modified() {

    always_assert( w.get() ) ;

    if( w->modified() ) {

      registry::read_from( last_filename() , ls , ps , false ) ;
      return true ;

    }

    return false ;

  }

private:

   lexer_style_t ls ;
  parser_style_t ps ;

  std::auto_ptr< cpl::util::file::file_name_watcher > w ;

} ;


} // namespace util

} // namespace cpl


#endif // CPP_LIB_UTIL_SYS_H
